package com.netty.esc.config.Thread;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.env.Environment;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 线程池配置
 */
@Slf4j(topic = "ThreadPool")
@Configuration
@SuppressWarnings("all")
public class ThreadPoolAutoConfiguration implements EnvironmentAware,Ordered {

    @Override
    public void setEnvironment(Environment environment) {
        log.info("@Springboot Starting [ThreadPool 配置启动] ");
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

    /**
     * 自定义线程池
     * @return
     */
    @Bean
    public ThreadPoolExecutor threadPoolExecutor() {
        //获取cpu核心数
        final int cpu = Runtime.getRuntime().availableProcessors();
        //设置核心线程池数量
        final int corePoolSize = cpu + 1;
        //设置线程池中最大线程数量
        final int maximumPoolSize = cpu * 2 + 1;
        //设置线程空闲时间，超时终止线程，线程池线程数量维持在核心线程池大小(corePoolSize)
        final long keepAliveTime = 1L;
        //设置空闲时间的时间单位
        final TimeUnit timeUnit = TimeUnit.SECONDS;
        //设置阻塞队列，用来存储等待执行的任务，如果当前线程数量已超过核心线程设定的数量，则把任务暂时存放在等待队列中
//        final int maxQueueNum = 1 << 7;
        //new CustomThreadFactory()：线程工程，用来创建线程
        //new ThreadPoolExecutor.AbortPolicy()：如果线程池已满，新的任务的处理方式
        return new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                timeUnit,
                new LinkedBlockingQueue<>(Integer.MAX_VALUE),
                new CustomThreadFactory(),
                //new ThreadPoolExecutor.AbortPolicy()
                new JobPolicy()
        );
    }

    /**
     * 线程工厂
     */
    private class CustomThreadFactory implements ThreadFactory {
        /**
         * 初始化线程名称时使用
         * 提供原子操作的Integer，线程安全的
         * AtomicInteger可以在并发情况下达到原子化更新，避免使用了synchronized，而且性能非常高。
         */
        private final AtomicInteger poolNumber = new AtomicInteger(1);
        /**
         * 指定当前线程的线程组，未指定时线程组为创建该线程所属的线程组
         */
        private final ThreadGroup group;
        /**
         * 构建线程实体时使用
         * 提供原子操作的Integer，线程安全的
         * AtomicInteger可以在并发情况下达到原子化更新，避免使用了synchronized，而且性能非常高。
         */
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        /**
         * 线程名称
         */
        private final String namePrefix;

        CustomThreadFactory() {
            //构建java安全管理器
            SecurityManager s = System.getSecurityManager();
            //判定使用java安全管理器的group还是默认当前线程的group
            group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
            //初始化线程名称
            namePrefix = "taskThread-" + poolNumber.getAndIncrement();
        }

        @Override
        public Thread newThread(Runnable runnable) {
            Thread thread = new Thread(group, runnable, namePrefix + threadNumber.getAndIncrement(), 0);
            // 设置不是守护线程
            if (thread.isDaemon()) {
                thread.setDaemon(false);
            }

            // 设置优先级为默认的
            if (thread.getPriority() != Thread.NORM_PRIORITY) {
                thread.setPriority(Thread.NORM_PRIORITY);
            }

            //为线程工厂设置defult异常处理方案，对所有execute提交任务生效
            thread.setDefaultUncaughtExceptionHandler((Thread thread1,Throwable e)->{
                log.error("线程:{} 执行出错(错误由线程工厂默认处理方法捕获),错误原因:{}",thread1.getName(),e.getMessage());
            });
            return thread;
        }
    }

    private class JobPolicy implements RejectedExecutionHandler {

        JobPolicy() { }

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            log.error("任务[{}]被线程池[{}]拒绝执行，可能线程池已达到负载上限或线程池已经处于非运行态", r.toString(), e.toString());
            throw new Error("线程池任务执行失败，可能线程池已达到负载上限或线程池已经处于非运行态");
        }
    }


}
